package com.easyUploader.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.jwtAutoConfiguration.Jwt;
import com.easyUploader.entity.dao.User;
import com.easyUploader.entity.dto.UserDto;
import com.easyUploader.entity.vo.UserUpdateVo;
import com.easyUploader.entity.vo.UserVo;
import com.easyUploader.mapper.UserMapper;
import com.easyUploader.property.LocalFileProperty;
import com.easyUploader.service.IUserService;
import com.easyUploader.threadHolder.UserThreadHolder;
import com.easyUploader.util.CodeUtil;
import com.easyUploader.util.FileUtil;
import com.security.event.UserDomainEventPublisher;
import com.security.service.AuthenticateService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 大忽悠
 * @since 2022年11月15日
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    private final LocalFileProperty localFileProperty;
    private final Jwt jwt;
    private final Object nameRepeatCheckLock =new Object();
    private final UserDomainEventPublisher domainEventPublisher;

    /**
     * 1.先校验验证码是否正确 <br>
     * 2.用户名是否重复 <br>
     * 3.如果用户没有选择指定头像,那么选择默认头像
     *
     * @return
     */
    @Transactional
    @Override
    public String register(UserVo userVo) throws IOException {
        //用户权限相关信息检查--必须同步
        synchronized (nameRepeatCheckLock){
            userVo.check(this);
        }
        //转换user
        User user = userVo.toUser();
        //保存用户
        save(user);
        //设置当前用户信息到线程上下文,因为下面初始化相关工作需要用到
        UserThreadHolder.set(user);
        //用户相关信息初始化
        userVo.init(localFileProperty);
        //发布领域事件
        domainEventPublisher.publishUserRegisterEvent(user.getUsername());
        //生成token返回
        return generatorToken(user);
    }

    /**
     * 验证码过期时间为30分钟
     *
     * @param eamil 校验邮箱格式
     */
    @Override
    public void sendCode(String eamil) {
        CodeUtil.codeExistCheck(eamil);
        CodeUtil.sendCodeAsync(eamil);
    }

    @Override
    public String login(String username, String password) {
        User user = getOne(new QueryWrapper<User>().eq("username", username).eq("password", password));
        Assert.notNull(user, "用户名或密码错误");
        UserThreadHolder.set(user);
        //生成token返回
        return generatorToken(user);
    }

    private String generatorToken(User user) {
        HashMap<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("sub", user.getUsername());
        claims.put("created", new Date());
        return jwt.generateToken(claims);
    }

    @Override
    public UserDto userInfo() {
        return UserThreadHolder.get();
    }

    @Override
    public void getHeadImgData(HttpServletResponse httpServletResponse, HttpServletRequest httpServletRequest) throws UnsupportedEncodingException {
        File uHeadImg=localFileProperty.getOnlineUserHeadImgFile();
        FileUtil.showFile(httpServletRequest,httpServletResponse,uHeadImg,uHeadImg.getName(),FileUtil.getSuffix(uHeadImg));
    }

    @Transactional
    @Override
    public void updateUser(UserUpdateVo userUpdateVo) throws IOException {
        //注册和更新的时候,都需要检查用户名是否重复
        synchronized (nameRepeatCheckLock){
            userUpdateVo.updateUsernameOrPwdIfNeed(this);
        }
        userUpdateVo.updateHeadImgIfNeed(this);
    }

    @Transactional
    @Override
    public void userCancel() {
        UserDto userDto = UserThreadHolder.get();
        userDto.delAllResourcesRecord();
        userDto.delAllBucketRecord();
        userDto.delUserRecord();
        userDto.delUserHomeDir();
    }

}
